<template>
  <div class="mainDiv">
    <div class="diagramDiv" id="diagramDiv">
    </div>
  </div>
</template>

<script setup lang="ts">
defineOptions({
  name: "DiyDiagram",
  inheritAttrs: false,
});
import router from "@/router";
import DesdiagramAPI, { DesdiagramPageVO, DesdiagramData } from "@/api/desdiagram";
const route = useRoute();

let paper = null;
let mainSet = null;

onMounted(() => {
  const diagram = document.getElementById("diagramDiv");
  let width = diagram.clientWidth;
  let height = diagram.clientHeight;
  paper = new Raphael("diagramDiv", width, height);
  mainSet = paper.set();

  let textList = []; // 文本集合，用于获取数据
  if (route.params.id){
    DesdiagramAPI.getById(route.params.id).then(({data}) => {
      if (data){
        mainSet = paper.set();
        let eleJson = JSON.parse(data.elements);
        for(let i = 0; i < eleJson.length; i++){
          let element = eleJson[i];
          let obj = null;
          switch (element.type){
            case "rect":
              obj = drawRect(paper, element.attrs["x"], element.attrs["y"], element.attrs["width"], element.attrs["height"], 
                element.attrs["stroke-width"], element.attrs["fill"], element.attrs["stroke"], element.attrs["rotate"]);
            break;
            case "circle":
              obj = drawCircle(paper, element.attrs["cx"], element.attrs["cy"], element.attrs["r"], 
                element.attrs["stroke-width"], element.attrs["fill"], element.attrs["stroke"]);
            break;
            case "ellipse":
              obj = drawEllipse(paper, element.attrs["cx"], element.attrs["cy"], element.attrs["rx"], element.attrs["ry"], 
                element.attrs["stroke-width"], element.attrs["fill"], element.attrs["stroke"], element.attrs["rotate"]);
            break;
            case "triangle":
              let path = element.attrs["path"];
              let width = path[2][1] - path[0][1];
              let height = path[0][2] - path[1][2];
              let x = path[0][1] + width / 2;
              let y = path[0][2] - height / 2;
              obj = drawTriangle(paper, x, y, width, height, element.attrs["stroke-width"], element.attrs["fill"], 
                element.attrs["stroke"], element.attrs["rotate"]);
            break;
            case "line":
              let linePath = element.attrs["path"];
              let lineWidth = linePath[1][1] - linePath[0][1];
              let lineX = linePath[0][1] + lineWidth / 2;
              let lineY = linePath[0][2];
              obj = drawLine(paper, lineX, lineY, lineWidth, element.attrs["stroke-width"], element.attrs["stroke"], 
                element.attrs["rotate"]);
            break;
            case "vline":
              let vlinePath = element.attrs["path"];
              let vlineheight = vlinePath[1][2] - vlinePath[0][2];
              let vlineX = vlinePath[0][1];
              let vlineY = vlinePath[0][2] + vlineheight / 2;
              obj = drawVerticalLine(paper, vlineX, vlineY, vlineheight, element.attrs["stroke-width"], element.attrs["stroke"], 
                element.attrs["rotate"]);
            break;
            case "image":
              obj = drawImage(paper, element.attrs["x"], element.attrs["y"], element.attrs["src"], element.attrs["width"], 
                element.attrs["height"], element.attrs["stroke-width"], element.attrs["rotate"]);
            break;
            case "text":
              obj = drawText(paper, element.attrs["x"], element.attrs["y"], element.attrs["text"], element.attrs["font-size"], 
                element.attrs["stroke-width"], element.attrs["fill"], element.attrs["stroke"], element.attrs["rotate"],
                element.attrs["dataSource"], element.attrs["column"]);
              textList.push(obj);
            break;
            case "set":
              obj = drawUserObj(element.children);
            break;
            default:
            break;
          }
          mainSet.push(obj);
        }
        initData(textList);
        mainSet.translate(100, 0);
      }
    })
  }

  // 10秒自动更新
  setInterval(s => {
    initData(textList);
  }, 10000)
});

/*
  * 初始化文本数据
*/
function initData(textList){
  for(let i = 0; i < textList.length; i++){
    let dataSource = textList[i].attrs["dataSource"];
    let column = textList[i].attrs["column"];
    if (dataSource && column){
      DesdiagramAPI.getDiagramData({ "dataSource": dataSource, "column": column }).then(({data}) => {
        if (data){
          textList[i].attr("text", data);
        }
      })
    }
  }
}

/*
  * 画矩形
  * params:画布,矩形横坐标,矩形纵坐标,矩形宽,矩形高,矩形边框,填充颜色,边框颜色,旋转角度
*/
function drawRect(paper, startX, startY, w, h, s, fill, stroke, rotate){
  //创建矩形
  let rect = paper.rect(startX, startY, w , h).attr({'fill':fill, 'stroke':stroke,'stroke-width':s}).toBack();
  if (rotate){
    rect.rotate(rotate, startX + w /2, startY + h / 2)
    rect.attrs["rotate"] = rotate
  }
  return rect;
}

/*
  * 画圆形
  * params:画布,圆形横坐标,圆形纵坐标,圆形半径,圆形边框,填充颜色,边框颜色
*/
function drawCircle(paper, startX, startY, radius, s, fill, stroke){
  //创建圆形
  let circle = paper.circle(startX, startY, radius).attr({'fill':fill, 'stroke':stroke,'stroke-width':s}).toBack();
  return circle;
}

/*
  * 画椭圆
  * params:画布,椭圆横坐标,椭圆纵坐标,椭圆宽度,椭圆高度,边框,填充颜色,边框颜色,旋转角度
*/
function drawEllipse(paper, startX, startY, w, h, s, fill, stroke, rotate){
  //创建椭圆
  let ellipse = paper.ellipse(startX, startY, w, h).attr({'fill':fill, 'stroke':stroke,'stroke-width':s}).toBack();
  if (rotate){
    ellipse.rotate(rotate, startX + w /2, startY + h / 2)
    ellipse.attrs["rotate"] = rotate
  }
  return ellipse;
}

/*
  * 画三角（等腰三角形）
  * params:画布,中心点横坐标,中心点纵坐标,宽度,高度,边框,填充颜色,边框颜色,旋转角度
*/
function drawTriangle(paper, startX, startY, w, h, s, fill, stroke, rotate){
  let path = "M" + (startX - w / 2) + " " + (startY + h / 2) + "L" + startX + " " + (startY - h / 2) + "L" + (startX + w / 2) + " " + (startY + h / 2) + "Z";
  let triangle = paper.path(path).attr({'fill':fill, 'stroke':stroke, 'stroke-width':s}).toBack();
  if (rotate){
    triangle.rotate(rotate, startX, startY)
    triangle.attrs["rotate"] = rotate
  }
  return triangle;
}

/*
  * 画横线
  * params:画布,中心点横坐标,中心点纵坐标,长度,线粗细,线颜色,旋转角度
*/
function drawLine(paper, startX, startY, l, s, stroke, rotate){
  let path = "M" + (startX - l / 2) + " " + startY + "L" + (startX + l / 2) + " " + startY;
  let line = paper.path(path).attr({'stroke':stroke, 'stroke-width':s}).toBack();
  if (rotate){
    line.rotate(rotate, startX, startY)
    line.attrs["rotate"] = rotate
  }
  return line;
}

/*
  * 画竖线
  * params:画布,中心点横坐标,中心点纵坐标,长度,线粗细,线颜色,旋转角度
*/
function drawVerticalLine(paper, startX, startY, l, s, stroke, rotate){
  let path = "M" + startX + " " + (startY - l / 2) + "L" + startX + " " + (startY + l / 2);
  let line = paper.path(path).attr({'stroke':stroke, 'stroke-width':s}).toBack();
  if (rotate){
    line.rotate(rotate, startX, startY)
    line.attrs["rotate"] = rotate
  }
  return line;
}

/*
  * 画图片
  * params:画布,中心点横坐标,中心点纵坐标,宽度,高度,边框,旋转角度
*/
function drawImage(paper, startX, startY, url, w, h, s, rotate){
  let image = paper.image(url, startX, startY, w, h).attr({'stroke-width':s}).toBack();
  if (rotate){
    image.rotate(rotate, startX + w /2, startY + h / 2)
    image.attrs["rotate"] = rotate
  }
  return image;
}

/*
  * 画文字
  * params:画布,中心点横坐标,中心点纵坐标,文字内容,文字大小,线宽,填充颜色,边框颜色,旋转角度,数据源,字段
*/
function drawText(paper, startX, startY, content, fontSize, strokeWidth, fill, stroke, rotate, dataSource, column){
  let text = paper.text(startX, startY, content)
    .attr({stroke: stroke, "stroke-width": strokeWidth,"font-size": fontSize,"text-anchor": "middle", "fill": fill}).toBack();
  if (rotate){
    text.rotate(rotate, startX, startY)
    text.attrs["rotate"] = rotate
  }
  if (dataSource){
    text.attrs["dataSource"] = dataSource
  }
  if (column){
    text.attrs["column"] = column
  }
  return text;
}

/*
  * 画用户自定义组件
  * params:组件元素集
*/
function drawUserObj(elements){
  let set = paper.set();
  parseUserObj(set, elements);
  
  set.toBack();
  return set;
}

/*
  * 遍历解析组件元素，汇总到set集合
  * set:组件元素集合
  * elements:组件元素
*/
function parseUserObj(set, elements){
  for(let i = 0; i < elements.length; i++){
    let element = elements[i];
    switch (element.type){
      case "rect":
        let rect = paper.rect(element.attrs["x"], element.attrs["y"], element.attrs["width"] , element.attrs["height"])
          .attr({'fill':element.attrs["fill"], 'stroke':element.attrs["stroke"],'stroke-width':element.attrs["stroke-width"]});
        if (element.attrs["rotate"]){
          rect.rotate(element.attrs["rotate"], element.attrs["x"] + element.attrs["width"] /2, element.attrs["y"] + element.attrs["height"] / 2);
          rect.attrs["rotate"] = element.attrs["rotate"];
        }
        set.push(rect);
      break;
      case "circle":
        let circle = paper.circle(element.attrs["cx"], element.attrs["cy"], element.attrs["r"])
          .attr({'fill':element.attrs["fill"], 'stroke':element.attrs["stroke"],'stroke-width':element.attrs["stroke-width"]});
        set.push(circle);
      break;
      case "ellipse":
        let ellipse = paper.ellipse(element.attrs["cx"], element.attrs["cy"], element.attrs["rx"], element.attrs["ry"])
          .attr({'fill':element.attrs["fill"], 'stroke':element.attrs["stroke"],'stroke-width':element.attrs["stroke-width"]});
        if (element.attrs["rotate"]){
          ellipse.rotate(element.attrs["rotate"], element.attrs["cx"] + element.attrs["rx"] /2, element.attrs["cy"] + element.attrs["ry"] / 2);
          ellipse.attrs["rotate"] = element.attrs["rotate"]
        }
        set.push(ellipse);
      break;
      case "triangle":
        let trianglePath = element.attrs["path"];
        let width = trianglePath[2][1] - trianglePath[0][1];
        let height = trianglePath[0][2] - trianglePath[1][2];
        let x = trianglePath[0][1] + width / 2;
        let y = trianglePath[0][2] - height / 2;

        let trianglePathStr = "M" + trianglePath[0][1] + " " + trianglePath[0][2] + "L" + trianglePath[1][1] + " " 
          + trianglePath[1][2] + "L" + trianglePath[2][1] + " " + trianglePath[2][2] + "Z";
        let triangle = paper.path(trianglePathStr).attr({'fill':element.attrs["fill"], 'stroke':element.attrs["stroke"],'stroke-width':element.attrs["stroke-width"]});
        if (element.attrs["rotate"]){
          triangle.rotate(element.attrs["rotate"], x, y)
          triangle.attrs["rotate"] = element.attrs["rotate"]
        }
        set.push(triangle);
      break;
      case "line":
        let linePath = element.attrs["path"];
        let lineWidth = linePath[1][1] - linePath[0][1];
        let lineX = linePath[0][1] + lineWidth / 2;
        let lineY = linePath[0][2];
        let linePathStr = "M" + linePath[0][1] + " " + linePath[0][2] + "L" + linePath[1][1] + " " + linePath[1][2];
        let line = paper.path(linePathStr).attr({'stroke':element.attrs["stroke"], 'stroke-width':element.attrs["stroke-width"]});
        if (element.attrs["rotate"]){
          line.rotate(element.attrs["rotate"], lineX, lineY)
          line.attrs["rotate"] = element.attrs["rotate"]
        }
        set.push(line);
      break;
      case "vline":
        let vlinePath = element.attrs["path"];
        let vlineHeight = vlinePath[1][2] - vlinePath[0][2];
        let vlineX = vlinePath[0][1];
        let vlineY = vlinePath[0][2] + vlineHeight / 2;
        let vlinePathStr = "M" + vlinePath[0][1] + " " + vlinePath[0][2] + "L" + vlinePath[1][1] + " " + vlinePath[1][2];
        let vline = paper.path(vlinePathStr).attr({'stroke':element.attrs["stroke"], 'stroke-width':element.attrs["stroke-width"]});
        if (element.attrs["rotate"]){
          vline.rotate(element.attrs["rotate"], vlineX, vlineY)
          vline.attrs["rotate"] = element.attrs["rotate"]
        }
        set.push(vline);
      break;
      case "image":
        let image = paper.image(element.attrs["src"], element.attrs["x"], element.attrs["y"], element.attrs["width"], element.attrs["height"])
          .attr({'stroke-width':element.attrs["stroke-width"]});
        if (element.attrs["rotate"]){
          image.rotate(element.attrs["rotate"], element.attrs["x"] + element.attrs["width"] / 2, element.attrs["y"] + element.attrs["height"] / 2);
          image.attrs["rotate"] = element.attrs["rotate"]
        }
        set.push(image);
      break;
      case "text":
        let text = paper.text(element.attrs["x"], element.attrs["y"], element.attrs["text"])
          .attr({stroke: element.attrs["stroke"], "stroke-width": element.attrs["stroke-width"],
          "font-size": element.attrs["font-size"],"text-anchor": "middle", "fill": element.attrs["fill"]});
        if (element.attrs["rotate"]){
          text.rotate(element.attrs["rotate"], element.attrs["x"], element.attrs["y"]);
          text.attrs["rotate"] = element.attrs["rotate"]
        }
        set.push(text);
      break;
      case "path":
        if (element.attrs["path"].length == 2){ // 直线
          let linePath = element.attrs["path"];
          if (linePath[1][2] == linePath[0][2]){ // 横线
            element.type = "line";
          }
          else{
            element.type = "vline";
          }
        }
        else{ // 三角
          element.type = "triangle";
        }
        parseUserObj(set, [element]);
      break;
      case "set":
        set.push(parseUserObj(set, element.children));
      break;
      default:
      break;
    }
  }
}
</script>

<style scoped>
  .mainDiv {
    width: 100%;
    min-height: calc(100vh - 60px);
  }
  .diagramDiv {
    width: 100%;
    min-height: calc(100vh - 60px);
  }
</style>
